#include<vector>
#include<iostream>
#include<pthread.h>
#include<semaphore.h>
using namespace std;


const int default_cap = 5;

template<class T>
class RingQueue 
{
public: 
  RingQueue()  :_cap(default_cap),c_pos(0),p_pos(0)
  {
    pthread_mutex_init(&consumer_mtx,nullptr);
    pthread_mutex_init(&producter_mtx,nullptr);
    sem_init(&data_sem,0,0);
    sem_init(&blank_sem,0,_cap);
    ringqueue.resize(_cap);
  }
  ~RingQueue()
  {
    pthread_mutex_destroy(&consumer_mtx);
    pthread_mutex_destroy(&producter_mtx);
    sem_destroy(&data_sem);
    sem_destroy(&blank_sem);
  }
  //问题：先申请信号量还是先加锁 
  //本质上都可以,但是如果先加锁再申请信号量,即使信号量的初始值设置的再大，还是得一个一个的申请，此时申请信号量的前提是竞争锁成功,本质还是单生产单消费
  //如果是先申请信号量再加锁:此时相当于把信号量预先分配给多个生产者/消费者,竞争锁的前提是申请信号量成功，此时其他线程释放锁之后，其余的线程就可以立马竞争锁，提高效率
  void push(const T& val)
  {
     sem_wait(&blank_sem);
     pthread_mutex_lock(&producter_mtx);
     ringqueue[p_pos] = val;
     p_pos++;
     p_pos %= _cap;
     sem_post(&data_sem);
     pthread_mutex_unlock(&producter_mtx);
  }
  void pop(T* out)
  {
      sem_wait(&data_sem); 
      pthread_mutex_lock(&consumer_mtx);
      *out = ringqueue[c_pos];
      c_pos++;
      c_pos %= _cap;
      sem_post(&blank_sem);
      pthread_mutex_unlock(&consumer_mtx);
  }
private:
  vector<T> ringqueue;
  pthread_mutex_t consumer_mtx; 
  pthread_mutex_t producter_mtx;
  int c_pos;
  int p_pos;
  sem_t data_sem;
  sem_t blank_sem;
  int _cap;
};

